package com.hejia.alauda.entity;

import static com.hejia.alauda.utils.Utils.ACCEPTANCE_BILL_TAG;
import static com.hejia.alauda.utils.Utils.NON_PERFORMING_ASSETS_TAG;
import static com.hejia.alauda.utils.Utils.QIANGUNFAN_TAG;
import static org.apache.commons.lang3.time.DateUtils.addDays;
import static org.springframework.util.CollectionUtils.isEmpty;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import javax.persistence.Column;

import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.joda.time.DateTime;

import com.fasterxml.jackson.annotation.JsonView;
import com.hejia.alauda.entity.example.FinancingExample;
import com.hejia.alauda.persistence.mybatis.FinancingMapper;
import com.hejia.alauda.service.CommonServiceImpl;
import com.hejia.alauda.utils.RateUtil;

/**
 * 金融产品 Created by Johnny(@hejiajinrong.com) on 14-8-29.
 */

@JsonIgnoreProperties(value = { "id", "createDate", "description",
		"appDescription", "insurance", "financialAsset" })
public class Product extends BaseEntity {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	
	public interface BaseDataView {};
	//"serial","name", "tags", "term","minTerm","interestRate","bonusRate","valueDateStr","settlementDate","riskDescription","totalAmount","soldAmount","startTime","endTime","remainsTime","riskLevel", "finalStatus","numberOfShoppers","minAmount","status","rookie"
	/**
	 * 产品状态
	 * 
	 * @author hyr
	 *
	 */
	public enum Status {

		/**
		 * 编辑
		 */
		EDITING,

		/**
		 * 上架
		 */
		PUBLISHED,

		/**
		 * 结束
		 */
		FINISHED,

		/**
		 * 到点发布
		 */
		TIME_PUBLISH,

		// 遗留状态，不能移除
		PRESELL, ONSELL, SOLDOUT, HONOUR;
	}
	
	
	public enum Tags{
		ROOKIE("rookie"), //新手
		ENTERPRISE("enterprise"),//企业
		ACTIVITY("activity");   //活动
		
		private Tags(String name){
			this.name = name;
		}
		
		public String toString(){
			return this.name;
		}
		
		private String name;
	}

	/**
	 * 产品类别
	 * 
	 * @author hyr
	 *
	 */
	public enum Category {
		
		/**
		 * 债转
		 */
		TRANSFER,
		
		
		/**
		 * 月享
		 */
		MONTH,

		/**
		 * 银票宝
		 */
		NOTE,

		/**
		 * 双月享
		 */
		DOUBLE,
		
		/**
		 * 季享
		 */
		SEASON,
		
		/**
		 * 月季享
		 */
		MONTHSEASON,
		

		/**
		 * 季享
		 */
		QUARTER,

		/**
		 * 钱滚翻
		 */
		CURRENT,
		/**
		 * 半年期产品
		 */
		HALF_A_YEAR,
		/**
		 * 一年期产品
		 */
		YEAR,
		/**
		 * 其它
		 */
		OTHER;
		
		public String getName() {

			String name = "未知";

			switch (this) {
			case NOTE:
				name = "银票宝";
				break;
			case HALF_A_YEAR:
				name = "双季汇";
				break;
			case YEAR:
				name = "年享";
				break;
			case MONTH:
				name = "月享";
				break;
			case QUARTER:
				name = "季享";
				break;
			case CURRENT:
				name = "钱滚翻";
				break;
			case TRANSFER:
				name = "债转";
				break;
			case DOUBLE:
				name = "双月享";
				break;
			case SEASON:
				name = "季享";
				break;
			case MONTHSEASON:
				name = "月季享";
				break;
			case OTHER:
				name = "其它";
				break;
			}

			return name;
		}
	}

	@Column
	private Category category; // 产品类别

	@Column
	@JsonView(BaseDataView.class)
	private String serial; // 产品编号

	@Column
	@JsonView(BaseDataView.class)
	private String name; // 名称

	@Column
	@JsonView(BaseDataView.class)
	private Integer term; // 期限(天为单位)
	
	@Column
	@JsonView(BaseDataView.class)
	private Integer minTerm; // 期限(天为单位)
	
	@Column
	@JsonView(BaseDataView.class)
	private BigDecimal interestRate; // 年化利率；固定利率产品使用，浮动利率产品此字段为空。

	@Column
	@JsonView(BaseDataView.class)
	private BigDecimal bonusRate; // 平台奖励利率

	@Column
	private Date valueDate; // 起息日

	@Column
	private BigDecimal displayTotalAmount;// 显示总金额

	@Column
	@JsonView(BaseDataView.class)
	private BigDecimal totalAmount; // 总金额

	@Column
	@JsonView(BaseDataView.class)
	private BigDecimal soldAmount; // 已售金额

	@JsonIgnore
	@Column
	private BigDecimal unpayAmount; // 未付金额(冻结金额)

	@Column
	@JsonView(BaseDataView.class)
	private Date startTime; // 起售时间

	@Column
	@JsonView(BaseDataView.class)
	private Date endTime; // 结束销售时间

	@Column
	@JsonView(BaseDataView.class)
	private String riskLevel; // 风险等级

	@Column
	@JsonView(BaseDataView.class)
	private String riskDescription;// 风险描述

	@Column
	
	private String description; // 项目描述

	@Column
	private String appDescription; // app版本项目描述

	@Column
	private String insurance; // 安全保障
	
	@Column
	private boolean enterprise;
	
	private Long remainTimes;

	@Column
	@JsonView(BaseDataView.class)
	private Integer numberOfShoppers;// 购买人数

	@Column
	@JsonView(BaseDataView.class)
	private BigDecimal minAmount; // 起购金额

	@Column
	private BigDecimal maxAmount; // 限购金额

	@Column
	private Integer sequnce;// 排序

	@Column
	private Date publishDate;// 发布日期

	@Column
	@JsonView(BaseDataView.class)
	private Status status;

	@Column
	private String remark; // 产品备注（比如送红包什么的）

	private String statusValue;// 状态值

	@Column
	private String supplier;

	@Column
	private ProductType type;// 产品分类

	@Column
	private String acceptingBank;// 承兑银行
	
	@Column
	private Date cashTime;// 兑付时间

	@Column
	private String activitys;// 活动ID集合

	@Column
	private Integer tag = 1; // 产品标签 1：倒计时售卖 2：在售 3：已兑付 4：已售完

	@Column
	private FinancialAsset financialAsset; // 金融资产

	@Column
	@JsonView(BaseDataView.class)
	private Boolean rookie; // 是否新手标

	@Column
	private String agreementNumber; // 资产转让协议产品部分编号

	@Column
	private String enterpriseCode; // 企业码，用于指定企业可购买的产品

	@Column
	private String channel;// 发布渠道
	
	@Column	
	private boolean completedValue; //满标起息
	
	/** 是否固定期限*/
	@JsonView(BaseDataView.class)
	private boolean fixedTerm;
	
	private List<ProductEarningsRule> earningsRules; // 收益规则
	
	public boolean getFixedTerm() {
		return this.minTerm == null || this.minTerm.equals(this.term);
	}

	public void setFixedTerm(boolean fixedTerm) {
		this.fixedTerm = fixedTerm;
	}
	
	@JsonView(BaseDataView.class)
	public Long getRemainsTime() {
		return (getStartTime().getTime() - new Date().getTime())/1000;
	}

	@JsonView(BaseDataView.class)
	public String getValueDateStr() {
		if(Category.TRANSFER.equals(this.category))
			return "立即起息";
		
		if(this.completedValue)
			return "满标起息";
		
		else
			return FastDateFormat.getInstance("yyyy.MM.dd").format(valueDate);
	};

	public Category getCategory() {
		if (category == null) {
			category = Category.OTHER;
		}
		return category;
	}

	public void setCategory(Category category) {
		this.category = category;
	}

	
	public boolean isEnterprise() {
		return enterprise;
	}

	public void setEnterprise(boolean enterprise) {
		this.enterprise = enterprise;
	}

	public String getCategoryName() {
		if (this.category == null) {
			return "未知";
		}
		return this.category.getName();
	}

	public String getSerial() {
		return serial;
	}

	public void setSerial(String serial) {
		this.serial = serial;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getTerm() {
		return term;
	}

	public void setTerm(Integer term) {
		this.term = term;
	}

	public Integer getMinTerm() {
		return minTerm;
	}

	public void setMinTerm(Integer minTerm) {
		this.minTerm = minTerm;
	}

	public BigDecimal getInterestRate() {
		return interestRate;
	}

	public BigDecimal getBonusRate() {
		return bonusRate;
	}

	public void setBonusRate(BigDecimal bonusRate) {
		this.bonusRate = bonusRate;
	}

	public void setInterestRate(BigDecimal interestRate) {
		this.interestRate = interestRate;
	}

	public Date getValueDate() {
		if (this.valueDate == null) {
			valueDate = new Date(0);
		}
		return valueDate;
	}

	public void setValueDate(Date valueDate) {
		this.valueDate = valueDate;
	}

	/**
	 * 获取到期日
	 * 
	 * @return 到期日
	 */
	public Date getDueDate() {

		if (this.valueDate == null || this.term == null) {
			return null;
		}

		DateTime dateTime = new DateTime(this.valueDate.getTime());
		dateTime = dateTime.plusDays(this.term - 1);

		return dateTime.toLocalDate().toDate();
	}

	public BigDecimal getTotalAmount() {
		return totalAmount;
	}

	public void setTotalAmount(BigDecimal totalAmount) {
		this.totalAmount = totalAmount;
	}

	public BigDecimal getUnpayAmount() {
		if (unpayAmount == null)
			return new BigDecimal(0);
		return unpayAmount;
	}

	public void setUnpayAmount(BigDecimal unpayAmount) {
		this.unpayAmount = unpayAmount;
	}

	public BigDecimal getSoldAmount() {
		if (soldAmount == null)
			return new BigDecimal(0);
		return soldAmount;
	}

	public void setSoldAmount(BigDecimal soldAmount) {
		this.soldAmount = soldAmount;
	}

	public Date getStartTime() {
		return startTime;
	}

	public void setStartTime(Date startTime) {
		this.startTime = startTime;
	}

	public Date getEndTime() {
		return endTime;
	}

	public void setEndTime(Date endTime) {
		this.endTime = endTime;
	}

	public String getRiskLevel() {
		return riskLevel;
	}

	public void setRiskLevel(String riskLevel) {
		this.riskLevel = riskLevel;
	}

	public String getDescription() {
		return "风险较低";
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Integer getNumberOfShoppers() {
		return numberOfShoppers;
	}

	public void setNumberOfShoppers(Integer numberOfShoppers) {
		this.numberOfShoppers = numberOfShoppers;
	}

	public Status getStatus() {
		return status;
	}

	public void setStatus(Status status) {
		this.status = status;
	}

	public BigDecimal getMinAmount() {
		return minAmount;
	}

	public void setMinAmount(BigDecimal minAmount) {
		this.minAmount = minAmount;
	}

	public String getRiskDescription() {
		if(this.getRiskLevel() == null)
			return null;
		
		switch(this.getRiskLevel()){
			case "R1":
				riskDescription = "较低风险";
				break;
				
			case "R2":
				riskDescription = "中等风险";
				break;
				
			case "R3":
				riskDescription =  "较高风险";
				break;
		}
		
		return riskDescription;
	}

	public void setRiskDescription(String riskDescription) {
		this.riskDescription = riskDescription;
	}

	public String getAppDescription() {
		return appDescription;
	}

	public void setAppDescription(String appDescription) {
		this.appDescription = appDescription;
	}

	public String getStatusValue() {
		statusValue = "未知";
		if (status == Status.EDITING) {
			statusValue = "编辑";
		} else if (status == Status.PUBLISHED) {
			statusValue = "上架";
		} else if (status == Status.FINISHED) {
			statusValue = "结束";
		} else if (status == Status.TIME_PUBLISH) {
			statusValue = "到点上架";
		}
		return statusValue;
	}

	public void setStatusValue(String statusValue) {
		this.statusValue = statusValue;
	}

	public Integer getSequnce() {
		return sequnce;
	}

	public void setSequnce(Integer sequnce) {
		this.sequnce = sequnce;
	}

	public void setPublishDate(Date publishDate) {
		this.publishDate = publishDate;
	}

	public BigDecimal getDisplayTotalAmount() {
		return displayTotalAmount;
	}

	public void setDisplayTotalAmount(BigDecimal displayTotalAmount) {
		this.displayTotalAmount = displayTotalAmount;
	}

	public Date getPublishDate() {
		return publishDate;
	}

	@JsonIgnore
	public boolean isStart() {
		return new Date().getTime() >= this.getStartTime().getTime();
	}

	/**
	 * 最终的实际利率（预期利率+平台赠送利率）
	 * 
	 * @return
	 */
	public BigDecimal getFinalRate() {
		BigDecimal rate = new BigDecimal(0);
		if (getInterestRate() != null) {
			rate = rate.add(getInterestRate());
		}
		if (getBonusRate() != null) {
			rate = rate.add(getBonusRate());
		}
		return rate;
	}

	@JsonView(BaseDataView.class)
	public String getFinalStatus() {
		String str = "UNKNOWN";
		if (getStatus().equals(Status.FINISHED)
				|| getStatus().equals(Status.PUBLISHED)) {
			if (isStart()) {
				if (new Date().getTime() > getEndTime().getTime()
						|| (getSoldAmount().doubleValue() >= getTotalAmount()
								.doubleValue() && getUnpayAmount()
								.doubleValue() <= 0)) {
					str = Status.SOLDOUT.toString();
					if ("true".equals(getRemark())) {
						str = Status.HONOUR.toString();
					}
				} else {
					str = Status.ONSELL.toString();
				}
			} else {
				str = Status.PRESELL.toString();
			}
		} else {
			str = getStatus().toString();
		}
		return str;
	}

	public String getRemark() {
		return remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}

	public String getSupplier() {
		return supplier;
	}

	public void setSupplier(String supplier) {
		this.supplier = supplier;
	}

	public BigDecimal getMaxAmount() {
		if (this.maxAmount == null) {
			maxAmount = new BigDecimal(500000);
		}
		return maxAmount;
	}

	public void setMaxAmount(BigDecimal maxAmount) {
		this.maxAmount = maxAmount;
	}

	public String getInsurance() {
		return insurance;
	}

	public void setInsurance(String insurance) {
		this.insurance = insurance;
	}

	public String getAcceptingBank() {
		return acceptingBank;
	}

	public void setAcceptingBank(String acceptingBank) {
		this.acceptingBank = acceptingBank;
	}

	public Date getCashTime() {
		return cashTime;
	}

	public void setCashTime(Date cashTime) {
		this.cashTime = cashTime;
	}

	public ProductType getType() {
		return type;
	}

	public void setType(ProductType type) {
		this.type = type;
	}

	public Date getRealValueDate() {
		return RateUtil.calculateValueDate(valueDate);
	}

	public long getRemainsSeconds() {
		Date now = RateUtil.getDate();
		Date start = DateUtils.setMilliseconds(getStartTime(), 0);
		return (start.getTime() - now.getTime()) / 1000;
	}

	public Date getExpiredDate() {
		return addDays(this.getValueDate(), this.getTerm() - 1);
	}
	
	@JsonView(BaseDataView.class)
	public Date getSettlementDate() {
		return addDays(this.getValueDate(), this.getTerm());
	}

	public List<String> getProductTags() {
		switch (getCategory()) {
		case CURRENT:
			return QIANGUNFAN_TAG;
		default:
			return name.indexOf("票据") > -1 || name.indexOf("银票") > -1 ? ACCEPTANCE_BILL_TAG
					: NON_PERFORMING_ASSETS_TAG;
		}
	}

	public String getActivitys() {
		return activitys;
	}

	public void setActivitys(String activitys) {
		this.activitys = activitys;
	}

	@JsonView(BaseDataView.class)
	public List<Tags> getTags(){
		List<Tags> retVal = new ArrayList<Tags>();
		if(this.rookie)
			retVal.add(Tags.ROOKIE);
		
		if(this.getActivitys() != null && this.getActivitys().length()>0)
			retVal.add(Tags.ACTIVITY);
		
		if(this.isEnterprise())
			retVal.add(Tags.ENTERPRISE); 
		
		if(this.name.contains("企盈宝"))
			retVal.add(Tags.ENTERPRISE); 
		return retVal;
	}
	
	
	public Integer getTag() {
		return tag;
	}

	public void setTag(Integer tag) {
		this.tag = tag;
	}

	public FinancialAsset getFinancialAsset() {
		return financialAsset;
	}

	public void setFinancialAsset(FinancialAsset financialAsset) {
		this.financialAsset = financialAsset;
	}

	public Boolean getRookie() {
		return rookie;
	}

	public void setRookie(Boolean rookie) {
		this.rookie = rookie;
	}

	public String getAgreementNumber() {
		return agreementNumber;
	}

	public void setAgreementNumber(String agreementNumber) {
		this.agreementNumber = agreementNumber;
	}

	public String getEnterpriseCode() {
		return enterpriseCode;
	}

	public void setEnterpriseCode(String enterpriseCode) {
		this.enterpriseCode = enterpriseCode;
	}

	public String getChannel() {
		return channel;
	}

	public void setChannel(String channel) {
		this.channel = channel;
	}

	public List<ProductEarningsRule> getEarningsRules() {
		if (earningsRules == null) {
			earningsRules = new ArrayList<>();
		}
		return earningsRules;
	}

	public void setEarningsRules(List<ProductEarningsRule> earningsRules) {
		this.earningsRules = earningsRules;
	}

	public String getMinRate() {
		if (getCategory() != null) {
			switch (getCategory()) {
			case CURRENT:
				if (!isEmpty(getEarningsRules())) {
					return getEarningsRules().get(0).getInterestRate()
							.toString();
				}
			default:
				break;
			}
		}
		return this.getInterestRate().toString();
	}

	public String getMaxRate() {
		if (getCategory() != null) {
			switch (getCategory()) {
			case CURRENT:
				if (!isEmpty(getEarningsRules())) {
					return getEarningsRules()
							.get(getEarningsRules().size() - 1)
							.getInterestRate().toString();
				}
			default:
				break;
			}
		}
		return this.getFinalRate().toString();
	}

	public String getFinalMinRate() {
		if (getCategory() != null) {
			switch (getCategory()) {
			case CURRENT:
				if (!isEmpty(getEarningsRules())) {
					return getEarningsRules().get(0).getFinalInterestRate()
							.toString();
				}
			default:
				break;
			}
		}
		return this.getInterestRate().toString();
	}

	public String getFinalMaxRate() {
		if (getCategory() != null) {
			switch (getCategory()) {
			case CURRENT:
				if (!isEmpty(getEarningsRules())) {
					return getEarningsRules()
							.get(getEarningsRules().size() - 1)
							.getFinalInterestRate().toString();
				}
			default:
				break;
			}
		}
		return this.getFinalRate().toString();
	}

	public boolean isCompletedValue() {
		return completedValue;
	}

	public void setCompletedValue(boolean completedValue) {
		this.completedValue = completedValue;
	}

	/**
	 * 获取投资收益
	 * @param amount	投资金额
	 * @return	投资收益
	 */
	public BigDecimal getInvestmentIncome(BigDecimal amount) {
		return new BigDecimal(
			amount.doubleValue()
			* (this.getFinalRate().doubleValue())
			/ 360 * this.getTerm()).setScale(2, RoundingMode.UP);
	}
	
	public boolean isRepaid() {
		if (getTag() != null && getTag().equals(3) && getId() != null) {
			FinancingExample example = new FinancingExample();
			example.appendCriterion("`status`=",
					Financing.Status.STATUS_PAYBACK);
			example.appendCriterion("`product_id`=", getId());
			FinancingMapper financingMapper = CommonServiceImpl.applicationContext
					.getBean(FinancingMapper.class);
			return financingMapper.countByExample(example) == 0;
		}
		return false;
	}
	
	
	public static ProductComparator newComparator(){
		return new ProductComparator();
	}
	
	static class ProductComparator implements Comparator<Product>{

		@Override
		public int compare(Product o1, Product o2) {
			if(o1.getRookie() && o2.getRookie())
				return 0;
			
			
			if(o1.getRookie() && !o2.getRookie())
				return 1;
			
			if(!o1.getRookie() && o2.getRookie())
				return -1;
			
			return 0;
		}
		
	}
}



